/**
 * ArvoreTipoAtividades.java
 * 
 * Este código foi baseado no exemplo do site do ZK: http://www.zkoss.org/zkdemo/tree/dynamic_tree
 *
 * Projeto: SGA-LEDS
 *
 * Rodrigo Soares Maia IFES - Instituto Federal do Espírito Santo - Campus Serra
 */
package controleInterno.cih;

import controleAtividades.cci.CtrlAtividades;
import controleAtividades.cih.TreeNode;
import controleAtividades.cih.AdvancedTreeModel;
import controleInterno.cci.CtrlInterno;
import controleAtividades.cdp.Atividade;
import controleInterno.cdp.CategoriaTipo;
import controleInterno.cdp.Colaborador;
import controleInterno.cdp.Projeto;
import controleInterno.cdp.TipoAtividade;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.DropEvent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.MouseEvent;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Button;
import org.zkoss.zul.DefaultTreeNode;
import org.zkoss.zul.Div;
import org.zkoss.zul.Hlayout;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;
import org.zkoss.zul.Menubar;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Tree;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.Treecol;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.TreeitemRenderer;
import org.zkoss.zul.Treerow;
import org.zkoss.zul.Window;

public class ArvoreTipoAtividades extends SelectorComposer<Component>
{
    private Map mapaArgumentos;
    
    @Wire
    private Div arvoreTipoAtividades;
    @Wire
    private Tree arvore;
    @Wire
    private Treecol categoria;
    @Wire
    private Treecol opcoes;
    @Wire
    private Menubar menu;
    @Wire
    private Menuitem menuNovoTipo;
    @Wire
    private Menuitem menuExcluirTipos;
    
    private AdvancedTreeModel tipoTreeModel;
    private CategoriaTipo ct;
    
    CtrlInterno ctrlI = CtrlInterno.getInstance();
    CtrlAtividades ctrlA = CtrlAtividades.getInstance();
    
    
    //TODO adaptar tudo para os tipos...
    public void doAfterCompose(Component comp) throws Exception
    {
        super.doAfterCompose(comp);
        
        mapaArgumentos = Executions.getCurrent().getArg();
        
        ct = (CategoriaTipo) mapaArgumentos.get("categoria");
        
        boolean cadastro = (boolean) mapaArgumentos.get("cadastro");
        
        if (cadastro != true)
        {
            menu.setVisible(false);
            opcoes.setVisible(false);
            
            arvore.setCheckmark(true);
            
            categoria.setWidth("100%");
        }
        
        tipoTreeModel = new AdvancedTreeModel(new ListaTipos(ctrlI.obterTipos(ct)).getRoot());
        
        tipoTreeModel.setMultiple(true);
        
        arvore.setItemRenderer(new TipoAtividadeTreeRenderer());
        arvore.setModel(tipoTreeModel);
        categoria.setLabel(ct.getNome());
        
        System.out.println("Quantidade: " + tipoTreeModel.getChildCount(tipoTreeModel._root));
        
            //setando a coluna nomeProjeto como "droppable"
            // Both category row and atividade row can be item dropped
            categoria.setDroppable("true");
            categoria.addEventListener(Events.ON_DROP, new EventListener<Event>()
            {
                @SuppressWarnings("unchecked")
                @Override
                public void onEvent(Event event) throws Exception
                {
                    // The dragged target is a TreeRow belongs to an
                    // Treechildren of TreeItem.
                    Treeitem draggedItem = (Treeitem) ((DropEvent) event).getDragged().getParent();
                    TreeNode draggedValue = (TreeNode) draggedItem.getValue();
                    int nos, posicao;
                    
                    //if (temPai(draggedValue.getData()))
                    if (((Atividade) draggedValue.getData()).getAtividadePai() != null) //se a atividade tiver um pai, ele eh tirado
                    {
                        nos = tipoTreeModel.getChildCount(tipoTreeModel._root);
                        posicao = nos;

                        tipoTreeModel.remove(draggedValue);

                        tipoTreeModel.insert(tipoTreeModel._root, posicao, posicao, new TreeNode[] {draggedValue});
                        
                        //tirando o pai da atividade que foi movida
                        ctrlA.trocaPai((Atividade) draggedValue.getData(), null);
                    }
                    else //senao, nada eh feito
                    {
                        //nao faz nada
                    }
                } 
            });
        
        
        //adicionando evento no boto de criar nova atividade 
        menuNovoTipo.addEventListener(Events.ON_CLICK, new EventListener<Event>()
            {
                @Override
                public void onEvent(Event event) throws Exception
                {
                    //adicionando um novo tipo
                    Map atributos = new HashMap();
                    int posicao;

                    atributos.put("nome", "Novo Tipo");
                    atributos.put("descricao", "Descrição...");
                    atributos.put("atividadePai", null);
                    atributos.put("categoria", ct);
                    
                    TipoAtividade novoTipo = ctrlI.salvarTipo(atributos);
                    TreeNode novoNo = new TreeNode(novoTipo);
                    novoNo.setNovo(true);
                    
                    int nos = tipoTreeModel.getChildCount(tipoTreeModel._root);
                    
                    if (nos > 0) //se existir algum tipo na arvore
                    {
                        posicao = nos;
                    }
                    else //se a arvore estiver vazia
                    {
                        posicao = 0;
                    }
                    
                    tipoTreeModel.insert(tipoTreeModel._root, posicao, posicao, new TreeNode[] {novoNo});
                }
            });
        
        //alterando os ids, para que fiquem sempre unicos...
        arvoreTipoAtividades.setId("div_" + ct.getId().toString());
        arvore.setId("arvore_" + ct.getId().toString());
        categoria.setId("categoria_" + ct.getId().toString());
        opcoes.setId("opcoes_" + ct.getId().toString());
        menu.setId("menu_" + ct.getId().toString());
        menuNovoTipo.setId("menuNovoTipo_" + ct.getId().toString());
        menuExcluirTipos.setId("menuExcluirTipos_" + ct.getId().toString());
    }

    /**
     * The structure of tree
     *
     * <pre>
     * &lt;treeitem>
     *   &lt;treerow>
     *     &lt;treecell>...&lt;/treecell>
     *   &lt;/treerow>
     *   &lt;treechildren>
     *     &lt;treeitem>...&lt;/treeitem>
     *   &lt;/treechildren>
     * &lt;/treeitem>
     * </pre>
     */
    private final class TipoAtividadeTreeRenderer implements TreeitemRenderer<TreeNode>
    {
        /**
         * Renderiza todos os nos da arvore.
         * @param treeItem
         * @param treeNode
         * @param index
         * @throws Exception 
         */
        @Override
        public void render(final Treeitem treeItem, TreeNode treeNode, int index) throws Exception
        {
            TreeNode atn = treeNode;
            TipoAtividade tipoAtividade = (TipoAtividade) atn.getData();
            Treerow dataRow = new Treerow();
            dataRow.setParent(treeItem);
            treeItem.setValue(atn);
            treeItem.setOpen(atn.isOpen());

            Hlayout hlAtividade = new Hlayout();
            Hlayout hlOpcao = new Hlayout();

            hlAtividade.appendChild(new Label(tipoAtividade.getNome()));

            Textbox t = new Textbox(tipoAtividade.getNome());
            t.setVisible(false);
            hlAtividade.appendChild(t);

            hlAtividade.setSclass("h-inline-block");

            //icone de nova atividade; criara uma atividade irma da clicada baseada nas propriedades da clicada
            
            Image plusIcon = new Image("/images/plus-icon.png");

            plusIcon.addEventListener(Events.ON_CLICK, new EventListener<Event>()
            {
                @Override
                public void onEvent(Event event) throws Exception
                {
//                    //adicionando uma nova atividade "irma" da de cima, se houver de cima
//                    Treeitem itemClicado = (Treeitem) ((MouseEvent) event).getTarget().getParent().getParent().getParent().getParent();
//                    TreeNode no = (TreeNode) itemClicado.getValue();
//                    Atividade a = (Atividade) no.getData();
//
//                    Map atributos = new HashMap();
//                    
//                    //Adicionando o usuario atual como alocado, pois ele tambem serah o responsavel
//                    List<Colaborador> alocados = new ArrayList<Colaborador>();
//                    alocados.add(c);
//
//                    atributos.put("descricao", "Nova Atividade");
//                    atributos.put("dataInicio", Calendar.getInstance());
//                    atributos.put("dataFim", Calendar.getInstance());
//                    atributos.put("progresso", 0.0);
//                    atributos.put("duracao", 0.0);
//                    atributos.put("projeto", p);
//
//                    if (temPai(a))
//                    {
//                        atributos.put("tipo", a.getTipo());
//                        atributos.put("responsavel", a.getResponsavel());
//                        atributos.put("atividadePai", a.getAtividadePai());
//                    }
//                    else
//                    {
//                        atributos.put("tipo", null);
//                        atributos.put("responsavel", c);
//                        atributos.put("atividadePai", null);
//                    }
//
//                    Atividade novaAtividade = ctrlI.salvarAtividade(atributos, ctrlI.obterColaboradoresAlocados(a));
//                    //pegando o indice do noh em que foi clicado para se adicionar na proxima, ou seja, em baixo
//                    int indexAtual = no.getParent().getIndex(no);
//                    TreeNode novoNo = new TreeNode(novaAtividade);
//                    novoNo.setNovo(true);
//                    tipoTreeModel.insert(tipoTreeModel._root, indexAtual+1, indexAtual+1, new TreeNode[] {novoNo});
                }
            });
            
            //icone de editar a atividade na propria linha (sem abrir outra janela)
            
            Image editIcon = new Image("/images/edit-icon.png");

            editIcon.addEventListener(Events.ON_CLICK, new EventListener<Event>()
            {
                @Override
                public void onEvent(Event event) throws Exception
                {
                    //pegando a linha em questao
                    Treerow treeRow = (Treerow) ((MouseEvent) event).getTarget().getParent().getParent().getParent();
                    
                    tornarEditavel(treeRow);
                }
            });
            
            //icone de salvar a atividade editada na propria linha
            
            Image okIcon = new Image("/images/ok-icon.png");

            okIcon.addEventListener(Events.ON_CLICK, new EventListener<Event>()
            {
                @Override
                public void onEvent(Event event) throws Exception
                {
                    System.out.println("opaentrounookicon!");
                    TreeNode noClicado = (TreeNode) ((Treeitem) event.getTarget().getParent().getParent().getParent().getParent()).getValue();

                    TipoAtividade ta = (TipoAtividade) noClicado.getData();

                    Treeitem itemClicado = (Treeitem) ((MouseEvent) event).getTarget().getParent().getParent().getParent().getParent();

                    Textbox textbox = (Textbox) itemClicado.getChildren().get(0).getChildren().get(0).getChildren().get(0).getChildren().get(1);

                    ta.setNome(textbox.getValue());

                    ctrlI.alterarTipo(ta);
                }
            });
            
            //icone de cancelar edicao da atividade na propria linha
            
            Image cancelIcon = new Image("/images/cancel-icon.png");

            cancelIcon.addEventListener(Events.ON_CLICK, new EventListener<Event>()
            {
                @Override
                public void onEvent(Event event) throws Exception
                {
                    //cancela
                    //somente atualiza a arvore
                    refreshArvore();
                }
            });
            
            //icone de excluir a atividade em questao
            
            Image deleteIcon = new Image("/images/lixeira-icon.png");

            deleteIcon.addEventListener(Events.ON_CLICK, new EventListener<Event>()
            {
                @Override
                public void onEvent(Event event) throws Exception
                {
                    //adicionando uma nova atividade "irma" da de cima, se houver de cima
                    Treeitem itemClicado = (Treeitem) ((MouseEvent) event).getTarget().getParent().getParent().getParent().getParent();
                    TreeNode no = (TreeNode) itemClicado.getValue();
                    TipoAtividade ta = (TipoAtividade) no.getData();

                    //TODO tentar deletar o item em questão
                    //TODO aqui q eh feita a verificacao para ver se tem filhas e perguntar?
                    
                    if (ctrlI.apagarTipo(ta))
                    {
                        tipoTreeModel.remove(no);
                    }
                }
            });

            //desabilitando os icones na linha
            plusIcon.setVisible(false);
            editIcon.setVisible(false);
            deleteIcon.setVisible(false);
            okIcon.setVisible(false);
            cancelIcon.setVisible(false);
            
            //setando os icones no hlayout; a ordem de adicao eh importante
            hlOpcao.appendChild(plusIcon);
            hlOpcao.appendChild(editIcon);
            hlOpcao.appendChild(deleteIcon);
            hlOpcao.appendChild(okIcon);
            hlOpcao.appendChild(cancelIcon);

            Treecell tcTipo = new Treecell();
            tcTipo.appendChild(hlAtividade);

            Treecell tcOpcao = new Treecell();
            tcOpcao.appendChild(hlOpcao);

            dataRow.setDraggable("true");

            dataRow.appendChild(tcTipo);
            dataRow.appendChild(tcOpcao);

            dataRow.addEventListener(Events.ON_DOUBLE_CLICK, new EventListener<Event>()
            {
                @Override
                public void onEvent(Event event) throws Exception
                {
                    TreeNode noClicado = (TreeNode) ((Treeitem) event.getTarget().getParent()).getValue();

                    //TODO criar janela para edicao!!
                    //ctrl.abrirEditarTipo((TipoAtividade) noClicado.getData());
                }
            });

            // Both category row and atividade row can be item dropped
            dataRow.setDroppable("true");
            dataRow.addEventListener(Events.ON_DROP, new EventListener<Event>()
            {
                @SuppressWarnings("unchecked")
                @Override
                public void onEvent(Event event) throws Exception
                {
                    // The dragged target is a TreeRow belongs to an
                    // Treechildren of TreeItem.
                    Treeitem draggedItem = (Treeitem) ((DropEvent) event).getDragged().getParent();
                    TreeNode draggedValue = (TreeNode) draggedItem.getValue();
                    Treeitem parentItem = treeItem.getParentItem();
                    tipoTreeModel.remove(draggedValue);
                    
//                    if (temPai((Atividade) ((TreeNode) treeItem.getValue()).getData()))
//                    {
//                        tipoTreeModel.add((TreeNode) treeItem.getValue(),
//                                new DefaultTreeNode[]
//                                {
//                                    draggedValue
//                                });
//                    }
//                    else
//                    {                       
//                        int index = parentItem.getTreechildren().getChildren().indexOf(treeItem);
//                        if (parentItem.getValue() instanceof TreeNode)
//                        {
//                            tipoTreeModel.insert((TreeNode) parentItem.getValue(), index, index,
//                                    new DefaultTreeNode[]
//                                    {
//                                        draggedValue
//                                    });
//                        }
//
//                    }
                    
                        tipoTreeModel.add((TreeNode) treeItem.getValue(),
                                new DefaultTreeNode[]
                                {
                                    draggedValue
                                });
                        
                        //trocando o pai da atividade que foi movida
                        TipoAtividade novoPai = (TipoAtividade) ((TreeNode)treeItem.getValue()).getData();
                        TipoAtividade raizDosFilhos = (TipoAtividade) draggedValue.getData();
                        ctrlI.trocaPai(raizDosFilhos, novoPai);
                } 
            });
            
            //evento para quando o mouse eh colocado sobre a linha
            dataRow.addEventListener(Events.ON_MOUSE_OVER, new EventListener<Event>()
            {
                @SuppressWarnings("unchecked")
                @Override
                public void onEvent(Event event) throws Exception
                {
                    //pegando a linha em questao
                    Treerow treeRow = (Treerow) ((MouseEvent) event).getTarget();
                    //pegando a imagem que esta num hlayout que esta na segunda celula da linha
                    Image plus = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(0);
                    Image edit = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(1);
                    Image delete = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(2);
                    plus.setVisible(true);
                    edit.setVisible(true);
                    delete.setVisible(true);
                }
            });
            
            //evento para quando o mouse foi tirado da linha
            dataRow.addEventListener(Events.ON_MOUSE_OUT, new EventListener<Event>()
            {
                @SuppressWarnings("unchecked")
                @Override
                public void onEvent(Event event) throws Exception
                {
                    //pegando a linha em questao
                    Treerow treeRow = (Treerow) ((MouseEvent) event).getTarget();
                    //pegando as imagens que estao num hlayout que esta na segunda celula da linha
                    Image plus = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(0);
                    Image edit = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(1);
                    Image delete = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(2);
                    plus.setVisible(false);
                    edit.setVisible(false);
                    delete.setVisible(false);
                }
            });
            
            //GAMBI verificar como se faz para forcar a chamada do evento de edicao ao criar a atividade
            if (atn.ehNovo())
            {
               atn.setNovo(false);
               tornarEditavel(dataRow);
            }
        }

        private boolean temPai(TipoAtividade ta)
        {
            return ta.getTipoPai() != null;
        }
        
        private void tornarEditavel(Treerow treeRow){
            //pegando as imagens que estao num hlayout que esta na segunda celula da linha
            Image plus = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(0);
            Image edit = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(1);
            Image delete = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(2);
            plus.setVisible(false);
            edit.setVisible(false);
            delete.setVisible(false);
            
            //removendo listeners
            Iterable iterable;
            Iterator iterator;
            
            iterable = treeRow.getEventListeners(Events.ON_MOUSE_OVER);
            iterator = iterable.iterator();
            while (iterator.hasNext())
            {
                //iterator.remove();
                treeRow.removeEventListener(Events.ON_MOUSE_OVER, (EventListener<Event>) iterator.next());
            }
            
            iterable = treeRow.getEventListeners(Events.ON_MOUSE_OUT);
            iterator = iterable.iterator();
            while (iterator.hasNext())
            {
                //iterator.remove();
                treeRow.removeEventListener(Events.ON_MOUSE_OUT, (EventListener<Event>) iterator.next());
            }
            
            //visible true nos inputs e false nos labels
            Label label = (Label) treeRow.getChildren().get(0).getChildren().get(0).getChildren().get(0);
            Textbox input = (Textbox) treeRow.getChildren().get(0).getChildren().get(0).getChildren().get(1);

            label.setVisible(false);
            input.setVisible(true);

            //visible true nos botoes ok e cancel
            //pegando a imagem que esta num hlayout que esta na segunda celula da linha
            Image ok = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(3);
            Image cancel = (Image) treeRow.getChildren().get(1).getChildren().get(0).getChildren().get(4);
            ok.setVisible(true);
            cancel.setVisible(true); //TODO criar metodo interno para dar visible true ou false nas imagens
            
            input.setFocus(true);
        }
    }
    
    public void refreshArvore()
    {
        arvore.setModel(arvore.getModel());
    }
}
